#
# Copyright 2010 iXsystems, Inc.
# All rights reserved
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted providing that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
#####################################################################
import logging
import os
import re

from django.utils.translation import ugettext_lazy as _

from dojango import forms
from freenasUI.common.forms import ModelForm
from freenasUI.freeadmin.forms import SelectMultipleWidget
from freenasUI.freeadmin.utils import key_order
from freenasUI.middleware.client import client
from freenasUI.middleware.exceptions import MiddlewareError
from freenasUI.middleware.notifier import notifier
from freenasUI.middleware.form import MiddlewareModelForm
from freenasUI.services.models import services, NFS
from freenasUI.sharing import models
from freenasUI.storage.widgets import UnixPermissionField
from ipaddr import (IPNetwork, AddressValueError, NetmaskValueError)

log = logging.getLogger('sharing.forms')


class CIFS_ShareForm(MiddlewareModelForm, ModelForm):

    cifs_default_permissions = forms.BooleanField(
        label=_('Apply Default Permissions'),
        help_text=_(
            'Recursively set appropriate default Windows permissions on share'
        ),
        required=False
    )
    middleware_attr_prefix = "cifs_"
    middleware_attr_schema = "cifs"
    middleware_plugin = "sharing.cifs"
    is_singletone = False

    def __init__(self, *args, **kwargs):
        super(CIFS_ShareForm, self).__init__(*args, **kwargs)
        if self.instance.id:
            self.fields['cifs_default_permissions'].initial = False
            self._original_cifs_vfsobjects = self.instance.cifs_vfsobjects
        else:
            self.fields['cifs_default_permissions'].initial = True
            self._original_cifs_vfsobjects = []

        key_order(self, 4, 'cifs_default_permissions', instance=True)

        self.fields['cifs_guestok'].widget.attrs['onChange'] = (
            'javascript:toggleGeneric("id_cifs_guestok", '
            '["id_cifs_guestonly"], true);')
        if self.data:
            if self.data.get('cifs_guestok') is False:
                self.fields['cifs_guestonly'].widget.attrs['disabled'] = \
                    'disabled'
        elif self.instance.cifs_guestok is False:
            self.fields['cifs_guestonly'].widget.attrs['disabled'] = 'disabled'
        self.fields['cifs_name'].required = False
        self.fields['cifs_home'].widget.attrs['onChange'] = (
            "cifs_storage_task_toggle();"
        )

        if self.instance:
            task_dict = {}
            if self.instance.cifs_path:
                with client as c:
                    task_dict = c.call('sharing.cifs.get_storage_tasks',
                                       self.instance.cifs_path)

            elif self.instance.cifs_home:
                with client as c:
                    task_dict = c.call('sharing.cifs.get_storage_tasks',
                                        None, self.instance.cifs_home)

            if task_dict:
                choices = [('', '-----')]
                for task_id, msg in task_dict.items():
                    choices.append((task_id, msg))
                self.fields['cifs_storage_task'].choices = choices

            else:
                self.fields['cifs_storage_task'].choices = (('', '-----'),)

    class Meta:
        fields = '__all__'
        model = models.CIFS_Share

    def middleware_clean(self, data):
        data['hostsallow'] = data['hostsallow'].split()
        data['hostsdeny'] = data['hostsdeny'].split()

        if not data['storage_task']:
            data.pop('storage_task')

        return data

    def done(self, request, events):
        if not services.objects.get(srv_service='cifs').srv_enable:
            events.append('ask_service("cifs")')
        super(CIFS_ShareForm, self).done(request, events)


class AFP_ShareForm(MiddlewareModelForm, ModelForm):
    middleware_attr_prefix = "afp_"
    middleware_attr_schema = "afp"
    middleware_plugin = "sharing.afp"
    is_singletone = False

    class Meta:
        fields = '__all__'
        model = models.AFP_Share

    def __init__(self, *args, **kwargs):
        super(AFP_ShareForm, self).__init__(*args, **kwargs)
        self.fields['afp_upriv'].widget.attrs['onChange'] = (
            'javascript:toggleGeneric("id_afp_upriv", ["id_afp_fperm", '
            '"id_afp_dperm", "id_afp_umask"], true);')
        self.fields['afp_fperm'] = UnixPermissionField(
            label=self.fields['afp_fperm'].label,
            initial=self.fields['afp_fperm'].initial,
            required=False,
        )
        self.fields['afp_dperm'] = UnixPermissionField(
            label=self.fields['afp_dperm'].label,
            initial=self.fields['afp_dperm'].initial,
            required=False,
        )
        if self.instance.id:
            if not self.instance.afp_upriv:
                self.fields['afp_fperm'].widget.attrs['disabled'] = 'true'
                self.fields['afp_dperm'].widget.attrs['disabled'] = 'true'
                self.fields['afp_umask'].widget.attrs['disabled'] = 'true'
            else:
                self.fields['afp_fperm'].widget.attrs['disabled'] = 'false'
                self.fields['afp_dperm'].widget.attrs['disabled'] = 'false'
                self.fields['afp_umask'].widget.attrs['disabled'] = 'false'
        self.fields['afp_name'].required = False

    def middleware_clean(self, data):
        data['allow'] = data['allow'].split()
        data['deny'] = data['deny'].split()
        data['ro'] = data['ro'].split()
        data['rw'] = data['rw'].split()
        data['hostsallow'] = data['hostsallow'].split()
        data['hostsdeny'] = data['hostsdeny'].split()

        return data

    def done(self, request, events):
        if not services.objects.get(srv_service='afp').srv_enable:
            events.append('ask_service("afp")')
        super(AFP_ShareForm, self).done(request, events)


class NFS_ShareForm(MiddlewareModelForm, ModelForm):
    middleware_attr_prefix = "nfs_"
    middleware_attr_schema = "sharingnfs"
    middleware_plugin = "sharing.nfs"
    is_singletone = False
    middleware_attr_map = {
        "networks": "nfs_network",
    }

    class Meta:
        fields = '__all__'
        model = models.NFS_Share
        widgets = {
            'nfs_security': SelectMultipleWidget(sorter=True),
        }

    def __init__(self, *args, **kwargs):
        super(NFS_ShareForm, self).__init__(*args, **kwargs)
        try:
            nfs = NFS.objects.order_by('-id')[0]
        except IndexError:
            nfs = NFS.objects.create()
        if not nfs.nfs_srv_v4:
            del self.fields['nfs_security']

    def middleware_clean(self, data):
        data["paths"] = [
            self.data[f"path_set-{i}-path"]
            for i in range(int(self.data["path_set-TOTAL_FORMS"][0]))
            if self.data[f"path_set-{i}-path"] and not self.data.get(f"path_set-{i}-DELETE")
        ]
        data["networks"] = data.pop("network").split()
        data["hosts"] = data["hosts"].split()
        data["security"] = [s.upper() for s in data.get("security", [])]

        return data

    def done(self, request, events):
        if not services.objects.get(srv_service='nfs').srv_enable:
            events.append('ask_service("nfs")')
        super(NFS_ShareForm, self).done(request, events)


class NFS_SharePathForm(ModelForm):

    class Meta:
        fields = '__all__'
        model = models.NFS_Share_Path

    def clean_path(self):
        path = self.cleaned_data.get('path')
        if path and ' ' in path:
            raise forms.ValidationError(_(
                'Whitespace is not a valid character for NFS shares.'
            ))
        return path

    def save(self, *args, **kwargs):
        path = self.cleaned_data.get('path').encode('utf8')
        if path and not os.path.exists(path):
            try:
                os.makedirs(path)
            except OSError as e:
                raise MiddlewareError(_(
                    'Failed to create %(path)s: %(error)s' % {
                        'path': path,
                        'error': e,
                    }
                ))
        return super(NFS_SharePathForm, self).save(*args, **kwargs)


class WebDAV_ShareForm(MiddlewareModelForm, ModelForm):

    middleware_attr_schema = 'webdav_share'
    middleware_attr_prefix = 'webdav_'
    middleware_plugin = 'webdav.share'
    is_singletone = False

    class Meta:
        fields = '__all__'
        model = models.WebDAV_Share

    def done(self, request, events):
        if not services.objects.get(srv_service='webdav').srv_enable:
            events.append('ask_service("webdav")')
        super(WebDAV_ShareForm, self).done(request, events)
